package main

import (
	"net/http"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

// 用户结构体
type User struct {
	ID       string
	Conn     *websocket.Conn
	RoomID   string
	LastPong time.Time // 用于记录最后一个Pong时间
}

// 用户管理器
type UserManager struct {
	sync.Mutex
	Users map[string]*User
}

var userManager = UserManager{
	Users: make(map[string]*User),
}

// 用户登录
func login(c *gin.Context) {
	userID := c.Query("userID")
	roomID := c.Query("roomID")

	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "升级连接失败"})
		return
	}

	user := &User{
		ID:     userID,
		Conn:   conn,
		RoomID: roomID,
	}

	userManager.Lock()
	userManager.Users[userID] = user
	userManager.Unlock()

	// 开始心跳
	go startHeartbeat(user)

	// 处理WebSocket通信
	go handleWebSocket(user)
}

// 处理WebSocket通信
func handleWebSocket(user *User) {
	defer user.Conn.Close()

	for {
		messageType, p, err := user.Conn.ReadMessage()
		if err != nil {
			// 用户下线
			userManager.Lock()
			delete(userManager.Users, user.ID)
			userManager.Unlock()
			break
		}

		// 重置最后的Pong时间
		if string(p) == "ping" {
			user.LastPong = time.Now()
		}

		// 广播消息
		userManager.Lock()
		for _, u := range userManager.Users {
			if u.RoomID == user.RoomID {
				err = u.Conn.WriteMessage(messageType, p)
				if err != nil {
					// 处理错误
				}
			}
		}
		userManager.Unlock()
	}
}

// 心跳机制
func startHeartbeat(user *User) {
	// 设置心跳周期为20秒
	PingTimer := time.NewTicker(20 * time.Second)
	defer PingTimer.Stop()

	for range PingTimer.C {
		// 检查最后的Pong时间，如果超时则认为连接异常(连续3次心跳超时，则认为连接异常)
		if time.Since(user.LastPong) > 65*time.Second {
			// 用户离线，删除连接
			userManager.Lock()
			delete(userManager.Users, user.ID)
			userManager.Unlock()
			user.Conn.Close()
			return
		}
		// 发送Ping
		err := user.Conn.WriteMessage(websocket.TextMessage, []byte("ping"))
		if err != nil {
			// 处理错误

		}
	}
}

func main() {
	r := gin.Default()
	r.GET("/login", login)
	r.Run(":8080")
}
